'''
项目名称：产业园区管理运营平台
文件名称：租后服务数据生成脚本
@Author: 王旭
@Contact: 1643959780@qq.com
@Created: 2025/06/28
@Version: V1.0

@Description:
本脚本用于为产业园区管理运营平台生成各类租户日常服务相关的测试数据。
它依赖于 `init_business.py` 生成的合同数据，为已签约的租户创建服务记录。
主要功能包括：
1. 创建物业报修服务记录。
2. 创建保洁预约服务记录。
3. 创建送水服务记录。
4. 创建装修备案申请记录。
5. 创建临时停车记录。

@Modifications:
- V1.0 (2025/06/28): 实现各种服务类数据生成。
'''

import os
import sys
import django
import random
import json
import datetime
from django.utils import timezone
from faker import Faker

# --- Start: 动态添加项目根目录到 sys.path ---
current_script_path = os.path.abspath(__file__)
script_dir = os.path.dirname(current_script_path)
project_root = os.path.dirname(script_dir)
sys.path.append(project_root)
# --- End: 动态添加项目根目录到 sys.path ---

# 设置Django环境
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'smartpark.settings')
django.setup()

# 导入模型
from django.db import transaction
from users.models import User, CompanyEmployeeProfile, ParkEmployeeProfile, Visitor, Company
from assets.models import Unit, Device, Vehicle
from services.models import (
    Contract, RepairService, WaterDeliveryService, 
    CleaningBookingService, DecorationApplication, TemporaryParkingService, 
    VisitorAppointmentService, DeviceMaintenance, LeasingApplicationService, 
    ParkingSpaceLeasingService
)

# 初始化Faker
fake = Faker('zh_CN')

# 配置参数
CONFIG = {
    "services_per_tenant": {
        "repair": 0.4,      # 80%的租户会报修
        "cleaning": 0.5,    # 50%的租户会预约保洁
        "water": 0.8,       # 80%的租户会订水
        "decoration": 0.2,  # 20%的租户会申请装修
    },
    "visitor_appointments": {
        "count": 50, # 生成的访客预约数量
        "purposes": ["业务洽谈", "面试", "参观", "送货", "维修设备", "商务会议", "产品展示", "培训", "咨询服务"]
    },
    "temp_parking": {
        "total_records": 500, # 生成的临时停车总记录数
        "free_hours": 2,      # 免费停车小时数
        "rate_per_hour": 5    # 每小时费率
    }
}

def clear_old_services_data():
    """清除所有的租后服务数据"""
    print("--- 正在清除旧的租后服务数据... ---")
    DeviceMaintenance.objects.all().delete()
    RepairService.objects.all().delete()
    CleaningBookingService.objects.all().delete()
    WaterDeliveryService.objects.all().delete()
    DecorationApplication.objects.all().delete()
    TemporaryParkingService.objects.all().delete()
    VisitorAppointmentService.objects.all().delete()
    print("旧的租后服务数据已清除。")

@transaction.atomic
def create_services_data():
    """创建所有租后服务数据"""
    print("--- 开始创建租后服务数据 ---")

    tenants = get_all_tenants()
    if not tenants:
        print("警告: 未找到任何租户信息，无法创建租后服务数据。")
        return

    park_employees = get_park_employees()
    repair_staff = park_employees.get('维修工', [])

    try:
        create_repair_services(tenants, repair_staff)
        create_cleaning_services(tenants, park_employees.get('保洁工', []))
        create_water_services(tenants, park_employees.get('配送员', []) or park_employees.get('送水工', []))
        create_decoration_applications(tenants)
        create_temporary_parking_services()
        create_visitor_appointments()
        create_inspection_records(repair_staff)

        print("\n租后服务数据生成完成！")
        print_statistics()
    except Exception as e:
        print(f"\n!!! 数据生成过程中发生错误，事务将回滚 !!!")
        print(f"错误详情: {e}")
        import traceback
        traceback.print_exc()

def get_all_tenants():
    """
    获取所有能享受服务的租户。
    基于合同中的乙方（公司或个人）来确定租户。
    """
    tenants = []
    
    # 查询所有生效中的合同
    active_contracts = Contract.objects.filter(status='生效中').select_related('unit', 'company', 'user')

    for contract in active_contracts:
        if not contract.unit:
            continue

        # 根据新的字段含义：
        # - company_id/user_id 字段表示"乙方"（承租方/企业或个人）
        # - party_b 字段表示"甲方主体"（出租方/园区）
        
        # 如果合同关联了企业，则该企业是租户
        if contract.company:
            # 获取该公司的所有员工
            company_employees = CompanyEmployeeProfile.objects.filter(company=contract.company).select_related('user')
            for emp_profile in company_employees:
                if emp_profile.user:
                    tenants.append({'user': emp_profile.user, 'unit': contract.unit})
        
        # 如果合同关联了个人用户，则该用户是租户
        elif contract.user:
            tenants.append({'user': contract.user, 'unit': contract.unit})

    if not tenants:
        print("警告：在 'get_all_tenants' 函数中，未能找到任何有效的租户。请检查 init_business.py 生成的合同数据。")

    return tenants

def get_park_employees():
    """获取并分类所有园区员工"""
    employees = {}
    profiles = ParkEmployeeProfile.objects.select_related('user').all()
    for profile in profiles:
        emp_type = profile.employee_type
        if emp_type not in employees:
            employees[emp_type] = []
        employees[emp_type].append(profile.user)
    return employees

def create_repair_services(tenants, repair_staff):
    print("\n创建物业报修服务...")
    if not repair_staff:
        print("警告: 没有维修工，无法创建报修服务。")
        return

    num_to_create = int(len(tenants) * CONFIG['services_per_tenant']['repair'])
    tenants_to_service = random.sample(tenants, min(num_to_create, len(tenants)))

    created_count = 0
    for tenant_info in tenants_to_service:
        user, unit = tenant_info['user'], tenant_info['unit']
        device = Device.objects.filter(unit=unit).order_by('?').first() or Device.objects.filter(building=unit.building).order_by('?').first()
        if not device: continue

        status = random.choice(['待受理', '已受理', '处理中', '已完成', '已评价', '已取消'])
        handler = random.choice(repair_staff) if status not in ['待受理', '已取消'] else None

        # 为已完成的报修生成更详细的数据
        completion_time, repair_result, repair_cost, rating, review_content = None, None, None, None, None
        
        if status in ['已完成', '已评价']:
            application_time = timezone.now() - datetime.timedelta(days=random.randint(2, 60))
            completion_time = application_time + datetime.timedelta(hours=random.randint(4, 72))
            repair_result = random.choice([f"更换了{device.device_name}的损坏零件，设备恢复正常。", "清洁了内部灰尘，问题解决。", "重新配置了系统参数，运行稳定。", "经检查为小问题，已当场修复。", "线路接触不良，已重新固定。"])
            repair_cost = random.choice([None, 0, 50, 100, 150, 200, 300, 500]) if repair_result else 0
            if status == '已评价':
                rating = random.randint(4, 5)
                review_content = random.choice(["维修师傅很专业，速度快！", "服务很好，问题很快就解决了。", "非常满意！谢谢师傅。", ""])
        else:
            application_time = timezone.now() - datetime.timedelta(hours=random.randint(1, 72))
        
        created_at_time = application_time or timezone.now()

        repair_service = RepairService.objects.create(
            applicant_user=user, 
            unit=unit, 
            device=device, 
            fault_description=f"{device.device_name} - {random.choice(['无法启动', '有异响', '屏幕不亮', '连接中断', '漏水', '反应迟钝'])}", 
            application_time=application_time, 
            status=status, 
            handler_user=handler,
            completion_time=completion_time,
            repair_result=repair_result,
            repair_cost=repair_cost,
            rating=rating,
            review_content=review_content,
            created_at=created_at_time, 
            updated_at=created_at_time
        )
        created_count += 1

        # 如果报修已完成，则同步创建一条"维修"类型的维保记录
        if status in ['已完成', '已评价']:
            responsible_person_name = "未知"
            if handler and hasattr(handler, 'parkemployeeprofile') and handler.parkemployeeprofile:
                responsible_person_name = handler.parkemployeeprofile.name
            
            DeviceMaintenance.objects.create(
                device=device,
                maintenance_type='维修',
                content=repair_result,
                responsible_person=responsible_person_name,
                maintenance_date=completion_time.date(),
                cost=repair_cost,
                repair_service=repair_service,
                created_at=completion_time,
                updated_at=completion_time
            )

    print(f"成功创建 {created_count} 条物业报修记录。")

def create_cleaning_services(tenants, cleaning_staff):
    print("\n创建保洁预约服务...")
    if not cleaning_staff: return
    num_to_create = int(len(tenants) * CONFIG['services_per_tenant']['cleaning'])
    tenants_to_service = random.sample(tenants, min(num_to_create, len(tenants)))
    created_count = 0
    for tenant_info in tenants_to_service:
        user = tenant_info['user']
        unit = tenant_info['unit']
        status = random.choice(['待受理', '已受理', '服务中', '已完成', '已评价', '已取消'])
        handler = random.choice(cleaning_staff) if status not in ['待受理', '已取消'] else None
        
        # 为已完成和已评价状态的保洁服务设置服务费用
        service_fee = 0
        if status in ['已完成', '已评价']:
            # 根据单元面积计算服务费用，或者使用固定价格范围
            if unit.actual_area:
                # 将Decimal转换为float，然后进行计算
                area_float = float(unit.actual_area)
                # 按面积计算：3-5元/平方米
                service_fee = round(area_float * random.uniform(3, 5), 2)
            else:
                # 固定价格范围：100-300元
                service_fee = random.randint(100, 300)
        
        CleaningBookingService.objects.create(
            applicant_user=user, 
            unit=unit, 
            expected_service_date=fake.date_between(start_date='+1d', end_date='+2w'), 
            expected_time_slot=random.choice(['上午', '下午']), 
            application_time=timezone.now(), 
            status=status, 
            handler_user=handler, 
            service_fee=service_fee,  # 添加服务费用字段
            created_at=timezone.now(), 
            updated_at=timezone.now()
        )
        created_count += 1
    print(f"成功创建 {created_count} 条保洁预约记录。")

def create_water_services(tenants, delivery_staff):
    print("\n创建送水服务...")
    if not delivery_staff: return
    num_to_create = int(len(tenants) * CONFIG['services_per_tenant']['water'])
    tenants_to_service = random.sample(tenants, min(num_to_create, len(tenants)))
    created_count = 0
    for tenant_info in tenants_to_service:
        user = tenant_info['user']
        unit = tenant_info['unit']
        status = random.choice(['待受理', '配送中', '已送达', '已评价', '已取消'])
        handler = random.choice(delivery_staff) if status not in ['待受理', '已取消'] else None
        unit_price = random.choice([20, 25, 30])
        quantity = random.randint(2, 10)
        WaterDeliveryService.objects.create(applicant_user=user, unit=unit, product_name=random.choice(['品牌A桶装水', '品牌B纯净水']), quantity=quantity, unit_price=unit_price, total_amount=unit_price*quantity, expected_delivery_time=timezone.now() + datetime.timedelta(hours=random.randint(2,24)), delivery_address=f"{unit.building.name} {unit.floor.actual_label} {unit.unit_number}", contact_name=user.companyemployeeprofile.name if hasattr(user, 'companyemployeeprofile') else user.parkemployeeprofile.name, contact_phone=user.phone, application_time=timezone.now(), status=status, deliverer_user=handler, created_at=timezone.now(), updated_at=timezone.now())
        created_count += 1
    print(f"成功创建 {created_count} 条送水服务记录。")

def create_decoration_applications(tenants):
    print("\n创建装修备案申请...")
    num_to_create = int(len(tenants) * CONFIG['services_per_tenant']['decoration'])
    tenants_to_service = random.sample(tenants, min(num_to_create, len(tenants)))
    created_count = 0
    for tenant_info in tenants_to_service:
        user, unit = tenant_info['user'], tenant_info['unit']
        staff_info = [{"name": fake.name(), "phone": fake.phone_number()} for _ in range(random.randint(2, 5))]
        DecorationApplication.objects.create(applicant_user=user, unit=unit, application_date=fake.date_this_year(), construction_company=f"{fake.company()}装饰", construction_staff_info=json.dumps(staff_info, ensure_ascii=False), estimated_duration=random.randint(15, 60), status=random.choice(['待审核', '审核通过', '施工中']), created_at=timezone.now(), updated_at=timezone.now())
        created_count += 1
    print(f"成功创建 {created_count} 条装修备案记录。")

def create_visitor_appointments():
    """创建访客预约服务"""
    print("\n创建访客预约服务...")
    inviters = list(CompanyEmployeeProfile.objects.select_related('user', 'company').all())
    visitors = list(Visitor.objects.all())

    if not inviters or not visitors:
        print("警告: 没有足够的员工或访客来创建访客预约。")
        return

    created_count = 0
    purposes = CONFIG['visitor_appointments']['purposes']

    for _ in range(CONFIG['visitor_appointments']['count']):
        try:
            inviter_profile = random.choice(inviters)
            visitor = random.choice(visitors)
            
            expected_visit_time = fake.date_time_this_year(tzinfo=timezone.get_current_timezone())
            
            today = timezone.now()
            if expected_visit_time < today:
                status = random.choices(['已离园', '已取消'], weights=[8, 2])[0]
            elif expected_visit_time.date() == today.date():
                status = random.choices(['待审批', '已批准', '已入园', '已离园', '已取消'], weights=[2, 4, 2, 1, 1])[0]
            else: # Future
                status = random.choices(['待审批', '已批准', '已取消'], weights=[7, 2, 1])[0]

            accompanier_count = random.randint(0, 2)
            accompanier_info = json.dumps(
                [{"name": fake.name(), "phone": fake.phone_number()} for _ in range(accompanier_count)],
                ensure_ascii=False
            ) if accompanier_count > 0 else "[]"
            
            VisitorAppointmentService.objects.create(
                inviter_user=inviter_profile.user,
                visited_company=inviter_profile.company,
                visitor=visitor,
                expected_visit_time=expected_visit_time,
                visit_purpose=random.choice(purposes),
                status=status,
                accompanier_info=accompanier_info
            )
            created_count += 1
        except Exception as e:
            print(f"创建访客预约失败: {e}")
            
    print(f"成功创建 {created_count} 条访客预约记录。")

def create_temporary_parking_services():
    print("\n创建临时停车服务记录...")
    vehicles = list(Vehicle.objects.select_related('user', 'visitor').all())
    created_count = 0
    for _ in range(CONFIG['temp_parking']['total_records']):
        # 模拟部分车辆仍在场内 (exit_time 为空)
        is_still_parked = random.random() < 0.3

        entry_time = fake.date_time_this_year(tzinfo=timezone.get_current_timezone())
        
        exit_time = None
        parking_duration = None
        payable_amount = 0

        if not is_still_parked:
            duration_hours = random.uniform(0.5, 10)
            exit_time = entry_time + datetime.timedelta(hours=duration_hours)
            chargeable_hours = max(0, duration_hours - CONFIG['temp_parking']['free_hours'])
            payable_amount = round(chargeable_hours * CONFIG['temp_parking']['rate_per_hour'], 2)
            parking_duration = int(duration_hours*60)
        
        vehicle = random.choice(vehicles) if vehicles and random.random() < 0.7 else None
        user = vehicle.user if vehicle and hasattr(vehicle, 'user') else None
        visitor = vehicle.visitor if vehicle and hasattr(vehicle, 'visitor') else None

        TemporaryParkingService.objects.create(
            vehicle=vehicle, 
            plate_number=vehicle.plate_number if vehicle else fake.license_plate(), 
            entry_time=entry_time, 
            exit_time=exit_time, 
            parking_duration=parking_duration,
            fee_rate=CONFIG['temp_parking']['rate_per_hour'], 
            payable_amount=payable_amount, 
            user=user, 
            visitor=visitor, 
            created_at=timezone.now(), 
            updated_at=timezone.now()
        )
        created_count += 1
    print(f"成功创建 {created_count} 条临时停车记录。")

def create_inspection_records(repair_staff):
    """为设备创建历史巡检记录"""
    print("\n创建设备定期巡检记录...")
    if not repair_staff:
        print("警告: 没有维修工，无法创建巡检记录。")
        return

    devices = Device.objects.all()
    created_count = 0
    for device in devices:
        if not device.maintenance_cycle or not device.purchase_date:
            continue

        # 从今天开始，按维保周期往过去生成巡检记录，直到设备的购买日期
        current_inspection_date = timezone.now().date() - datetime.timedelta(days=random.randint(5, device.maintenance_cycle))

        while current_inspection_date > device.purchase_date:
            handler = random.choice(repair_staff)
            responsible_person_name = "未知"
            if handler and hasattr(handler, 'parkemployeeprofile') and handler.parkemployeeprofile:
                responsible_person_name = handler.parkemployeeprofile.name
            
            # 将date对象转换为aware datetime对象以避免时区警告
            inspection_datetime = datetime.datetime.combine(current_inspection_date, datetime.time.min)
            aware_datetime = timezone.make_aware(inspection_datetime, timezone.get_current_timezone())

            DeviceMaintenance.objects.create(
                device=device,
                maintenance_type='巡检',
                content=random.choice([
                    "设备例行巡检，一切正常。",
                    "检查设备运行状态，无异常发现。",
                    "对设备进行清洁和基础测试，符合标准。",
                    "巡检完成，已记录设备各项参数，均在正常范围内。"
                ]),
                responsible_person=responsible_person_name,
                maintenance_date=current_inspection_date,
                cost=0,
                repair_service=None,
                created_at=aware_datetime,
                updated_at=aware_datetime
            )
            created_count += 1
            # 基于维保周期往前推，增加一点随机性，使其不完全固定
            current_inspection_date -= datetime.timedelta(days=device.maintenance_cycle + random.randint(-7, 7))
    
    print(f"成功创建 {created_count} 条设备巡检记录。")

def print_statistics():
    """打印数据统计信息"""
    print("\n=== 租后服务数据统计 ===")
    print(f"物业报修记录总数: {RepairService.objects.count()}")
    print(f"设备维保记录总数: {DeviceMaintenance.objects.count()}")
    print(f"保洁预约记录总数: {CleaningBookingService.objects.count()}")
    print(f"送水服务记录总数: {WaterDeliveryService.objects.count()}")
    print(f"装修备案记录总数: {DecorationApplication.objects.count()}")
    print(f"临时停车记录总数: {TemporaryParkingService.objects.count()}")
    print(f"访客预约记录总数: {VisitorAppointmentService.objects.count()}")

if __name__ == "__main__":
    clear_old_services_data()
    create_services_data() 